home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / documents / Inventor / www / workarounds / Text3Core.2.0.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  14.1 KB  |  418 lines

  1. //
  2. // This is a patch for the Inventor 2.0 Text3 node, which will
  3. // core dump when given an character code in the range 128-255.
  4. //
  5. // To apply this patch, compile this file into a .o and then link
  6. // the .o before -lInventor.  You will also need to link with -lFL,
  7. // the internal, undocumented font library that Inventor uses (sorry,
  8. // no, a public, released, documented version is NOT available).
  9. // The linker may give a warning about
  10. // multiply defined symbols. This is normal and expected.
  11. //
  12.  
  13. #include <Inventor/caches/SoGLRenderCache.h>
  14. #include <Inventor/elements/SoCacheElement.h>
  15. #include <Inventor/elements/SoComplexityElement.h>
  16. #include <Inventor/elements/SoComplexityTypeElement.h>
  17. #include <Inventor/elements/SoCreaseAngleElement.h>
  18. #include <Inventor/elements/SoFontNameElement.h>
  19. #include <Inventor/elements/SoFontSizeElement.h>
  20. #include <Inventor/elements/SoGLCacheContextElement.h>
  21. #include <Inventor/elements/SoGLTextureCoordinateElement.h>
  22. #include <Inventor/elements/SoGLTextureEnabledElement.h>
  23. #include <Inventor/elements/SoMaterialBindingElement.h>
  24. #include <Inventor/elements/SoModelMatrixElement.h>
  25. #include <Inventor/elements/SoProfileElement.h>
  26. #include <Inventor/elements/SoProfileCoordinateElement.h>
  27. #include <Inventor/elements/SoProjectionMatrixElement.h>
  28. #include <Inventor/elements/SoViewportRegionElement.h>
  29. #include <Inventor/elements/SoViewingMatrixElement.h>
  30. #include <Inventor/errors/SoDebugError.h>
  31. #include <Inventor/misc/SoState.h>
  32. #include <Inventor/nodes/SoText3.h>
  33. #include <Inventor/nodes/SoProfile.h>
  34.  
  35. #include <GL/gl.h>
  36.  
  37. // Internal font library stuff from the unshipped flclient.h.
  38. // DO NOT TRY TO USE THIS!
  39. class SoFontOutline;
  40. typedef GLint FLfontNumber;
  41. typedef struct __FLcontextRec *FLcontext;
  42. #define FL_HINT_AABITMAPFONTS   1      /* bound to font                    */
  43. #define FL_HINT_CHARSPACING     2      /* bound to font                    */
  44. #define FL_HINT_FONTTYPE        3      /* bound to font                    */
  45. #define FL_HINT_MAXAASIZE       4      /* bound to font                    */
  46. #define FL_HINT_MINOUTLINESIZE  5      /* bound to font                    */
  47. #define FL_HINT_ROUNDADVANCE    6      /* bound to font                    */
  48. #define FL_HINT_SCALETHRESH     7      /* bound to font                    */
  49. #define FL_HINT_TOLERANCE       8      /* bound to font                    */
  50.  
  51. extern "C" {
  52.  
  53. FLfontNumber flCreateFont(
  54.     const GLubyte *                /* fontName */,
  55.     GLfloat [2][2]                 /* mat */, 
  56.     GLint                          /* charNameCount */,
  57.     GLubyte **                     /* charNameVector */
  58. );
  59. void flSetHint(
  60.     GLuint                         /* hint */, 
  61.     GLfloat                        /* hintValue */
  62. );
  63. GLboolean flMakeCurrentFont(
  64.     FLfontNumber                   /* fn */
  65. );
  66. };
  67.  
  68. //
  69. // Internal class: SoOutlineFontCache
  70. //
  71.  
  72. // Callback function for sides of characters-- passed the number of
  73. // points going back, and points and normals on either edge of the
  74. // strip.  tTexCoords[0] and [1] are for the two edges, and the
  75. // sTexCoords are the same for both edges.
  76. typedef void SideCB(int nPoints,
  77.             const SbVec3f *points1, const SbVec3f *norms1,
  78.             const SbVec3f *points2, const SbVec3f *norms2,
  79.             const float *sTexCoords, const float *tTexCoords);
  80.  
  81. // This is pretty heavyweight-- it is responsible for doing all of the
  82. // grunt work of figuring out the polygons making up the characters in
  83. // the font.
  84. class SoOutlineFontCache : public SoGLRenderCache
  85. {
  86.   public:
  87.     // Given a state, find an appropriate outline font.
  88.     static SoOutlineFontCache    *getFont(SoState *, SbBool forRender);
  89.     
  90.     // Checks to see if this font is valid
  91.     SbBool    isValid(SoState *state) const;
  92.  
  93.     // Figures out if this cache is valid for rendering (the base
  94.     // class isValid can be used for all other actions)
  95.     SbBool    isRenderValid(SoState *state) const;
  96.  
  97.     // Returns the width of given string
  98.     float    getWidth(const SbString &string);
  99.     
  100.     // Returns height of font
  101.     float    getHeight() { return fontSize; }
  102.  
  103.     // Returns the 2D bounding box of a character
  104.     void    getCharBBox(const char c, SbBox2f &result);
  105.     // ... and the bounding box of the font's bevel
  106.     void    getProfileBBox(SbBox2f &result);
  107.     
  108.     // Return the first/last point in the profile:
  109.     void    getProfileBounds(float &firstZ, float &lastZ);
  110.  
  111.     // Returns TRUE if there _is_ any profile
  112.     // (if not, act as if SIDES of text are off)
  113.     SbBool    hasProfile() const { return  (nProfileVerts > 1); }
  114.  
  115.     // Returns how far to advance after drawing given character:
  116.     SbVec2f    getCharOffset(const char c);
  117.     
  118.     // Uses the given glu tesselator to generate triangles for the
  119.     // given character.  This is used for both rendering and
  120.     // generating primitives, with just different callback routines
  121.     // registered.
  122.     void    generateFrontChar(const char c, GLUtriangulatorObj *tobj);
  123.     // Ditto, for sides of characters:
  124.     void    generateSideChar(const char c, SideCB callbackFunc);
  125.  
  126.     // Set up for GL rendering:
  127.     void    setupToRenderFront(SoState *state);
  128.     void    setupToRenderSide(SoState *state);
  129.  
  130.     // Returns TRUE if this font cache has a display list for the
  131.     // given character.  It will try to build a display list, if it
  132.     // can.
  133.     SbBool    hasFrontDisplayList(const char c, GLUtriangulatorObj *tobj);
  134.     SbBool    hasSideDisplayList(const char c, SideCB callbackFunc);
  135.  
  136.     // Renders an entire string by using the GL callList() function.
  137.     void    callFrontLists(const SbString &string);
  138.     void    callSideLists(const SbString &string);
  139.  
  140.     // Renders a string in cases where display lists can't be buit.
  141.     void    renderFront(const SbString &string,
  142.                 GLUtriangulatorObj *tobj);
  143.     void    renderSide(const SbString &string,
  144.                SideCB callbackFunc);
  145.  
  146.     // Callback registered with GLU used to detect tesselation errors.
  147.     static void errorCB(GLenum whichErr);
  148.  
  149.   protected:
  150.  
  151.     // Free up display lists before being deleted
  152.     virtual void    destroy(SoState *state);
  153.  
  154.   private:
  155.     // Constructor
  156.     SoOutlineFontCache(SoState *);
  157.     // Destructor
  158.     ~SoOutlineFontCache();
  159.  
  160.     // Return a convnient little class representing a character's
  161.     // outline.
  162.     SoFontOutline    *getOutline(const char c);
  163.     
  164.     // Some helper routines for generateSide:
  165.     void figureSegmentNorms(SbVec2f *result, int nPoints,
  166.      const SbVec2f *points, float cosCreaseAngle, SbBool isClosed);
  167.     void figureSegmentTexCoords(float *texCoords, int nPoints,
  168.      const SbVec2f *points, SbBool isClosed);
  169.     void fillBevel(SbVec3f *result, int nPoints, 
  170.            const SbVec2f *points, const SbVec2f &translation,
  171.            const SbVec2f &n1, const SbVec2f &n2);
  172.     void fillBevelN(SbVec3f *result, int nPoints, 
  173.             const SbVec2f *norms, const SbVec2f &n);
  174.  
  175.     // Cache context
  176.     int        cacheContext;
  177.  
  178.     // Number of characters in this font. Until we internationalize,
  179.     // this will be 256 or less.
  180.     int        numChars;
  181.  
  182.     // Starting index of blocks of display lists for front/sides:
  183.     GLuint    frontListBase;
  184.     GLuint    sideListBase;
  185.  
  186.     // Profile information:
  187.     float    cosCreaseAngle;
  188.     long    nProfileVerts;    // Number of points in profile
  189.     SbVec2f    *profileVerts;    // Profile vertices
  190.     float    *sTexCoords;    // Texture coordinates along profile
  191.                     // (nProfileVerts of them)
  192.     SbVec2f    *profileNorms;    // Profile normals
  193.                 // ((nProfileVerts-1)*2 of them)
  194.  
  195.     // This flag will be true if there is another cache open (if
  196.     // building GL display lists for render caching, that means we
  197.     // can't also build display lists).
  198.     SbBool    otherOpen;
  199.  
  200.     // And tables telling us if a display list has been created for
  201.     // each character in the font (we do that lazily since it is
  202.     // expensive):
  203.     SbBool    *frontFlags;
  204.     SbBool    *sideFlags;
  205.  
  206.     // List of outlines; these are also cached and created when
  207.     // needed.
  208.     SoFontOutline    **outlines;
  209.  
  210.     // Font size
  211.     float    fontSize;
  212.  
  213.     // Flag used to detect tesselation errors:
  214.     static SbBool tesselationError;
  215.  
  216.     // Font library identifier for this font
  217.     FLfontNumber    fontId;
  218.  
  219.     // Font library context for all outline fonts
  220.     static FLcontext    context;
  221.  
  222.     // Global list of available fonts; a 'font' in this case is a
  223.     // unique set of font name, font size, complexity value/type, and
  224.     // set of profiles-- if any of these changes, the set of polygons
  225.     // representing the font will change, and a different font will be
  226.     // used.
  227.     static SbPList    *fonts;
  228. };
  229.  
  230.  
  231. ////////////////////////////////////////////////////////////////////////
  232. //
  233. // Description:
  234. //    Constructor.  Called by getFont().
  235. //
  236. // Use: private
  237.  
  238. SoOutlineFontCache::SoOutlineFontCache(SoState *state) : 
  239.     SoGLRenderCache(state)
  240. //
  241. ////////////////////////////////////////////////////////////////////////
  242. {
  243.     ref();
  244.  
  245.     // Tell base class to ignore overridden elements in isValid
  246.     // check-- this is safe because the only relevant elements are
  247.     // guaranteed to already be on the elementsUsed list, so we're
  248.     // sure to detect changes to them.
  249.     setCompareOverridden(FALSE);
  250.  
  251.     cacheContext = -1;
  252.  
  253.     // Add element dependencies explicitly here; making 'this' the
  254.     // CacheElement doesn't work if we are being constructed in an
  255.     // action that doesn't have caches.
  256.     SbName font = SoFontNameElement::get(state);
  257.     addElement(state->getConstElement(
  258.     SoFontNameElement::getClassStackIndex()));
  259.     if (font == SoFontNameElement::getDefault()) {
  260.     font = SbName("Utopia-Regular");
  261.     }
  262.     
  263.     float uems;
  264.     
  265.     // Remember size
  266.     fontSize = SoFontSizeElement::get(state);
  267.     addElement(state->getConstElement(
  268.     SoFontSizeElement::getClassStackIndex()));
  269.     
  270.     // Figure out complexity...
  271.     float complexity = SoComplexityElement::get(state);
  272.     addElement(state->getConstElement(
  273.     SoComplexityElement::getClassStackIndex()));
  274.     addElement(state->getConstElement(
  275.     SoComplexityTypeElement::getClassStackIndex()));
  276.  
  277.     switch (SoComplexityTypeElement::get(state)) {
  278.       case SoComplexityTypeElement::OBJECT_SPACE:
  279.     {
  280.         // Two ramps-- complexity of zero  == 250/1000 of an em
  281.         //             complexity of .5    == 20/1000 of an em
  282.         //             complexity of 1     == 1/1000 of an em
  283.         const float ZERO = 250;
  284.         const float HALF = 20;
  285.         const float ONE = 1;
  286.         if (complexity > 0.5) uems = (2.0-complexity*2.0)*(HALF-ONE)+ONE;
  287.         else uems = (1.0-complexity*2.0)*(ZERO-HALF)+HALF;
  288.     }
  289.     break;
  290.  
  291.       case SoComplexityTypeElement::SCREEN_SPACE:
  292.     {
  293.         SbVec3f p(fontSize, fontSize, fontSize);
  294.         SbVec2s rectSize;
  295.         
  296.         SoShape::getScreenSize(state, SbBox3f(-p, p), rectSize);
  297.         float maxSize =
  298.         (rectSize[0] > rectSize[1] ? rectSize[0] : rectSize[1]);
  299.         uems = 250.0 / (1.0 + 0.25 * maxSize * complexity *
  300.                 complexity);
  301.         
  302.         // We have to manually add the dependency on the
  303.         // projection, view and model matrix elements (these are
  304.         // gotten in the SoShape::getScreenSize routine), and the
  305.         // ViewportRegionElement:
  306.         addElement(state->getConstElement(
  307.         SoProjectionMatrixElement::getClassStackIndex()));
  308.         addElement(state->getConstElement(
  309.         SoViewingMatrixElement::getClassStackIndex()));
  310.         addElement(state->getConstElement(
  311.         SoModelMatrixElement::getClassStackIndex()));
  312.         addElement(state->getConstElement(
  313.         SoViewportRegionElement::getClassStackIndex()));
  314.     }
  315.     break;
  316.  
  317.       case SoComplexityTypeElement::BOUNDING_BOX:
  318.     {
  319.         uems = 20;
  320.     }
  321.     break;
  322.     }
  323.     flSetHint(FL_HINT_TOLERANCE, uems);
  324.  
  325.     static GLfloat m[2][2] = { 1.0, 0.0, 0.0, 1.0 };
  326.  
  327.     fontId = flCreateFont((const GLubyte *)font.getString(), m, 0, NULL);
  328.  
  329.     // If error creating font:
  330.     if (fontId == 0) {
  331.     // Try Utopia-Regular, unless we just did!
  332.     if (font != SbName("Utopia-Regular")) {
  333. #ifdef DEBUG
  334.         SoDebugError::post("SoText3::getFont",
  335.               "Couldn't find font %s, replacing with Utopia-Regular",
  336.                font.getString());
  337. #endif
  338.         fontId = flCreateFont((GLubyte *)"Utopia-Regular", m, 0, NULL);
  339.     }
  340.     if (fontId == 0) {
  341. #ifdef DEBUG
  342.         SoDebugError::post("SoText3::getFont",
  343.                    "Couldn't find font Utopia-Regular!");
  344. #endif
  345.         return;
  346.     }
  347.     }
  348.  
  349.     flMakeCurrentFont(fontId);
  350.  
  351.     numChars = 256;  // ??? NEED TO REALLY KNOW HOW MANY CHARACTERS IN
  352.              // FONT!
  353.     frontListBase = 0;
  354.     sideListBase = 0;
  355.  
  356.     frontFlags = new SbBool[numChars];
  357.     sideFlags = new SbBool[numChars];
  358.     outlines = new SoFontOutline*[numChars];
  359.     for (int i = 0; i < numChars; i++) {
  360.     frontFlags[i] = sideFlags[i] = FALSE;
  361.     outlines[i] = NULL;
  362.     }
  363.  
  364.     // Get profile info:
  365.     const SoNodeList &profiles = SoProfileElement::get(state);
  366.     addElement(state->getConstElement(
  367.     SoProfileElement::getClassStackIndex()));
  368.     addElement(state->getConstElement(
  369.     SoProfileCoordinateElement::getClassStackIndex()));
  370.     nProfileVerts = 0;
  371.     if (profiles.getLength() > 0) {
  372.     SoProfile *profileNode = (SoProfile *)profiles[0];
  373.     profileNode->getVertices(state, nProfileVerts, profileVerts);
  374.     } else {
  375.     nProfileVerts = 2;
  376.     profileVerts = new SbVec2f[2];
  377.     profileVerts[0].setValue(0, 0);
  378.     profileVerts[1].setValue(1, 0);
  379.     }    
  380.  
  381.     if (nProfileVerts > 1) {
  382.     cosCreaseAngle = cos(SoCreaseAngleElement::get(state));
  383.     addElement(state->getConstElement(
  384.         SoCreaseAngleElement::getClassStackIndex()));
  385.     int nSegments = (int) nProfileVerts - 1;
  386.  
  387.     // Figure out normals for profiles; there are twice as many
  388.     // normals as segments.  The two normals for each segment endpoint
  389.     // may be averaged with the normal for the next segment, depending
  390.     // on whether or not the angle between the segments is greater
  391.     // than the creaseAngle.
  392.     profileNorms = new SbVec2f[nSegments*2];
  393.     figureSegmentNorms(profileNorms, (int) nProfileVerts, profileVerts,
  394.                cosCreaseAngle, FALSE);
  395.     // Need to flip all the normals because of the way the profiles
  396.     // are defined:
  397.     for (i = 0; i < nSegments*2; i++) {
  398.         profileNorms[i] *= -1.0;
  399.     }
  400.     
  401.     // Figure out S texture coordinates, which run along the profile:
  402.     sTexCoords = new float[nProfileVerts];
  403.     figureSegmentTexCoords(sTexCoords, (int) nProfileVerts,
  404.                    profileVerts, FALSE);
  405.     // And reverse them, so 0 is at the back of the profile:
  406.     float max = sTexCoords[nProfileVerts-1];
  407.     for (i = 0; i < nProfileVerts; i++) {
  408.         sTexCoords[i] = max - sTexCoords[i];
  409.     }
  410.     } else {
  411.     profileNorms = NULL;
  412.     sTexCoords = NULL;
  413.     }
  414.  
  415.     fonts->append(this);
  416. }
  417.  
  418.